﻿using IotModel;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Protocol;
using MQTTnet.Server;
using System.Text;

namespace IotClientApp.Server.MqttClient
{
    public class DeviceMQTTClient
    {
        private readonly ILogger<DeviceMQTTClient> _logger;
        internal IMqttClient mqttClient;
        public DeviceMQTTClient(ILogger<DeviceMQTTClient> logger)
        {
            _logger = logger;
        }
        private string _deviceId;
        private string _productId;
        private List<DeviceTopicModel> _deviceTopics;
        private Action<string, string, DeviceTopicModel, string, string> _action;
        private async Task Subscribe()
        {
            if (_deviceTopics != null && _deviceTopics.Count() > 0)
            {
                foreach (var _deviceTopic in _deviceTopics)
                {
                    await mqttClient.SubscribeAsync(_deviceTopic.TopicName, MqttQualityOfServiceLevel.AtMostOnce);
                }
            }
        }
        public async Task Publish(string topicName, string message)
        {
            var messagebuilder = new MqttApplicationMessageBuilder()
                .WithTopic(topicName)
                .WithPayload(message)
                .WithQualityOfServiceLevel(MQTTnet.Protocol.MqttQualityOfServiceLevel.AtLeastOnce)
                //.WithExactlyOnceQoS()
                //.WithAtLeastOnceQoS()                
                .WithRetainFlag(false)
                .Build();
            await mqttClient.PublishAsync(messagebuilder);
        }
        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="serverIp"></param>
        /// <param name="port"></param>
        /// <param name="authUser"></param>
        /// <param name="authPwd"></param>
        /// <param name="clientId"></param>
        /// <returns></returns>
        public async Task Init(string deviceId, string serverIp, int port, string authUser, string authPwd, List<DeviceTopicModel> deviceTopics, string clientId = "", Action<string, string, DeviceTopicModel, string, string> action = null)
        {
            if (string.IsNullOrEmpty(clientId))
            {
                clientId = $"{deviceId}_{DateTime.Now.Ticks}";
            }
            _action = action;
            _deviceTopics = deviceTopics;
            _deviceId = deviceId;
            try
            {
                var factory = new MqttFactory();
                mqttClient = factory.CreateMqttClient();
                var options = new MqttClientOptionsBuilder()
                    .WithTcpServer(serverIp, port)
                    .WithCredentials(authUser, authPwd)
                    .WithCleanSession(false)
                    .WithClientId(clientId)
                    .Build();
                if (action != null)
                {
                    mqttClient.ApplicationMessageReceivedAsync += MqttClient_ApplicationMessageReceivedAsync;
                    //mqttClient.ApplicationMessageReceivedAsync(e =>
                    //{
                    //    action(e.ApplicationMessage.Topic, Encoding.UTF8.GetString(e.ApplicationMessage.Payload));
                    //    //Console.WriteLine("###收到消息####");
                    //    //Console.WriteLine($"Topic {e.ApplicationMessage.Topic}");
                    //    //Console.WriteLine($"Payload {Encoding.UTF8.GetString(e.ApplicationMessage.Payload)}");
                    //    //Console.WriteLine($"Qos {e.ApplicationMessage.QualityOfServiceLevel}");
                    //    //Console.WriteLine($"Retain {e.ApplicationMessage.Retain}");
                    //    //Console.WriteLine();
                    //});
                }
                mqttClient.DisconnectedAsync += async e =>
                {
                    Console.WriteLine($"连接异常{deviceId}");
                    await Task.Delay(TimeSpan.FromSeconds(5));
                    try
                    {
                        await mqttClient.ConnectAsync(options);
                        //订阅
                        await Subscribe();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"{deviceId}重新连接服务器异常 {ex.Message}");
                        _logger.LogError($"{deviceId}重新连接服务器异常 {ex.Message}");
                    }
                };
                await mqttClient.ConnectAsync(options);
                await Subscribe();
            }
            catch (Exception ex)
            {
                _logger.LogError($"Init{ex.Message}");
            }
        }
        public async Task Stop()
        {
            await mqttClient.DisconnectAsync();
            mqttClient.Dispose();
        }
        private Task MqttClient_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs arg)
        {
            var deviceTopic = _deviceTopics.FirstOrDefault(t => t.TopicName == arg.ApplicationMessage.Topic);
            _action(_productId, _deviceId, deviceTopic, arg.ApplicationMessage.Topic, Encoding.UTF8.GetString(arg.ApplicationMessage.Payload));
            return Task.CompletedTask;
        }
    }
}